package davelha.server;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Vector;

import davelha.common.BaseGameInterface;
import davelha.common.Game;
import davelha.common.Player;

public class Server extends UnicastRemoteObject implements Runnable, BaseServerInterface{
	
	/**
	 * 
	 */
	private static final long	serialVersionUID	= -6526469561489004462L;
	public static final int		SERVER_STATUS_STOPED	= 0;
	public static final int		SERVER_STATUS_STARTED	= 1;
	public static final int		SERVER_STATUS_RUNNNING	= 2;

	private Vector<Game>		gamesVector				= null;
	private Vector<String>		gamesId					= null;
	private int					serverStatus			= 0;
	private String				serverName				= null;
	private int					lastGameId				= 0;
	private int					lastPlayerId			= 0;
	private Vector<Player>      playersVector           = null;
	
	private static final int	serverSleepTime			= 2000;
	
	
	public Server(String serverName) throws RemoteException{
		this.serverStatus = Server.SERVER_STATUS_STARTED;
		this.serverName = serverName;
		
		//inicializa o vetor de jogadores
		playersVector = new Vector();
	}
	
	//Roda o servidor de jogo
	public void run(){
		Game game = null;
		
		this.serverStatus = Server.SERVER_STATUS_RUNNNING;
		
		//Mensagem Informativa de console
		System.out.println("Servidor " + this.serverName + " rodando...");
		
		try {
			while(this.serverStatus == Server.SERVER_STATUS_RUNNNING){			
				
				//Verifica e atualiza a lista de jogos
				if(this.gamesVector != null){
					
					//Percorre o vetor de jogos
					for(int i = 0; i < gamesVector.size(); i++){
						//game = gamesVector.elementAt(i);

						if(gamesVector.elementAt(i).getGameState() 
								== BaseGameInterface.STATE_GAME_FINISHED){
							gamesVector.removeElementAt(i);
						}
					}
					
				}
				
				//Manda o servidor dormi por breves tempos
				try {
					Thread.sleep(serverSleepTime);
				} catch (InterruptedException e) {				
					System.out.print("Problemas na thread principal do servidor: " + e.getMessage());
				}
			}
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	@Override
	public Vector<Game> retrieveGameList() throws RemoteException {
		if(this.gamesVector != null){
			System.out.println(gamesVector.elementAt(0).getGameName());
			return this.gamesVector;
		}
		
		return null;
	}
	
	public String getServerName() throws RemoteException {
		return serverName;
	}	
	
	/**
	 * Cria um novo jogo sem inicializa-lo
	 * @param gameName
	 * @param player1
	 * @return
	 * @throws RemoteException
	 */
	public boolean createNewGame(String gameName, Player player1) throws RemoteException{
		System.out.println("New game created by user: " + player1.getName());
		
		Game game = new Game(gameName);
		lastGameId += 1;
		game.setGameId(lastGameId);
		game.setPlayer1(player1);
		game.setGameState(Game.STATE_WAITING_PLAYER);
		
		if(gamesId == null)
			gamesId = new Vector();
		
		//Registra o jogo na rede
		try {
			//Naming.rebind(gameName, game);
			//TODO: Teste
			Naming.rebind("rmi://localhost/Game" + game.getGameId(), game);
			gamesId.addElement("Game" + game.getGameId()); //Converte o id para string
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		
		if(gamesVector != null)
			gamesVector.add(game);
		else{
			gamesVector = new Vector<Game>();
			gamesVector.add(game);
		}
		return false;
	}

	public static void main(String args[]){
		//Cria e inicializa um novo servidor
		Thread threadServer = null;
		Server server = null;
		String msg = null;

		try {
			System.out.println("Iniciando servidor...");
			server = new Server("Teste do Tio Edu");
			threadServer = new Thread(server);
			Naming.rebind("rmi://localhost/Server", server); //Registra o objeto RMI
			System.out.println("Servidor inicializado...");
		} catch (RemoteException e) {
			msg = "Exception ao registrar o servidor RMI: " + e.getMessage(); 
			//e.printStackTrace();
		} catch (MalformedURLException e) {
			msg = "Exception ao inicializar o servidor: " + e.getMessage();
			//e.printStackTrace();
		}
		
		if(msg != null){
			System.out.println(msg);
			System.exit(0);
		}else{
			threadServer.start();
		}
		
	}

	@Override
	public Vector<String> retrieveGamesRmiId() throws RemoteException {
		return this.gamesId;
	}
	
	@Override
	public int addPlayerToServer(Player player) throws RemoteException{
		
		if(player != null){
			this.lastPlayerId +=1;
			player.setPlayerId(this.lastPlayerId);
			this.playersVector.addElement(player);
			return this.lastPlayerId;
		}
		
		return 0;
	}
		
	public boolean connectToGame(Player player, int gameId) throws RemoteException{
		//Verifica se o jogo está disponível
		//Game game = this.getGame(gameId);
		int gameIndex = this.getGameIndex(gameId);
		
		if(gameIndex >= 0){
			if(gamesVector.elementAt(gameIndex).getPlayer2() != null){
				return false;
			}else{
				gamesVector.elementAt(gameIndex).setPlayer2(player);
				gamesVector.elementAt(gameIndex).setGameState(
						Game.STATE_WAITING_PLAYER_ONE_CONFIRMATION);
				return true;
				
			}
		}
			
		return false;
	}
	
	private Game getGame(int gameId){
		
		try {
			for(int i = 0; i < gamesVector.size(); i++){
				if(gamesVector.elementAt(i).getGameId() == gameId)
					return gamesVector.elementAt(i);
			}
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	private int getGameIndex(int gameId){
		
		try {
			for(int i = 0; i < gamesVector.size(); i++){
				if(gamesVector.elementAt(i).getGameId() == gameId)
					return i;
			}
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		
		return -1;
	}

	@Override
	public Vector<BaseGameInterface> getPlayerGames(Player player) throws RemoteException {
		
		Vector<BaseGameInterface> vectorReturn = new Vector<BaseGameInterface>();
		
		if(gamesVector != null){
			for(int i = 0; i < gamesVector.size(); i++){
				if(gamesVector.elementAt(i).getPlayer1().getPlayerId() ==
					player.getPlayerId()){
					vectorReturn.addElement(gamesVector.elementAt(i));
				}
			}
		}
		
		if(vectorReturn.size() > 0)
			return vectorReturn;
		
		return null;
	}

	@Override
	public void setGameStatus(int gameId, int gameStatus)
			throws RemoteException {
		
		if(this.gamesVector != null){
			int gameIndex = getGameIndex(gameId);
			
			if(gameIndex >= 0){
				this.gamesVector.elementAt(gameIndex).setGameState(gameStatus);
			}
		}
	}

	@Override
	public Vector<BaseGameInterface> getPlayerChallengeGames(Player player)
			throws RemoteException {
		
		Vector<BaseGameInterface> vectorReturn = new Vector<BaseGameInterface>();
		
		if(gamesVector != null){
			for(int i = 0; i < gamesVector.size(); i++){
				if(gamesVector.elementAt(i).getPlayer2() != null){
					if(gamesVector.elementAt(i).getPlayer2().getPlayerId() ==
						player.getPlayerId()){
						vectorReturn.addElement(gamesVector.elementAt(i));
					}
				}
			}
		}
		
		if(vectorReturn.size() > 0)
			return vectorReturn;
		return null;
	}
	
	/**
	 * Remove o player 2 do servidor
	 */
	public void removePlayer2FromGame(int gameId) throws RemoteException{
		gamesVector.elementAt(getGameIndex(gameId)).setPlayer2(null);
	}
	
	/**
	 * Remove um jogo do servidor
	 */
	public boolean removeGameAt(int gamePos) throws RemoteException{
		try {
			if((gamesVector.elementAt(gamePos).getGameState() 
					== BaseGameInterface.STATE_BEGINING) 
					|| (gamesVector.elementAt(gamePos).getGameState() 
							== BaseGameInterface.STATE_WAITING_PLAYER)
					|| (gamesVector.elementAt(gamePos).getGameState() 
							== BaseGameInterface.STATE_GAME_FINISHED)){
				gamesVector.removeElementAt(gamePos);
				return true;
			}
		} catch (Exception e) {
			throw new RemoteException("Nao foi possivel remover o elemento" +
					e.getMessage());
		}
		return false;
	}
	
	/**
	 * Remove um jogo pelo id
	 * @param gameId
	 * @return
	 * @throws RemoteException
	 */
	public boolean removeGame(int gameId) throws RemoteException{
		
		if(gamesVector != null){
			for(int i = 0; i < gamesVector.size(); i++)
				if(gamesVector.elementAt(i).getGameId() == gameId){
					if(this.removeGameAt(i)){
						return true;
					}else{
						return false;
					}
				}
		}
		
		return false;
	}
		
}
